package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.aliyun.iot20180120.Client;
import com.aliyun.iot20180120.models.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageResponse;
import com.zzyl.constant.CacheConstants;
import com.zzyl.dto.DeviceDto;
import com.zzyl.entity.Device;
import com.zzyl.enums.BasicEnum;
import com.zzyl.enums.DeviceLocationTypeEnum;
import com.zzyl.enums.DevicePhysicalLocationTypeEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.DeviceMapper;
import com.zzyl.properties.AliIoTConfigProperties;
import com.zzyl.service.DeviceService;
import com.zzyl.vo.DeviceVo;
import com.zzyl.vo.ProductVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Description DeviceServiceImpl
 * @Author loe
 * @Date 2024-07-23
 */
@Service
public class DeviceServiceImpl implements DeviceService {

    @Autowired
    private Client client;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private AliIoTConfigProperties aliIoTConfigProperties;

    @Autowired
    private DeviceMapper deviceMapper;

    @Override
    public void syncProductList() {
        QueryProductListRequest request = new QueryProductListRequest();
        request.setPageSize(10);
        request.setCurrentPage(1);
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryProductListResponse response = null;
        try {
            response = client.queryProductList(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_LIST_PRODUCT_ERROR);
        }
        if (ObjectUtil.isEmpty(response)) {
            throw new BaseException(BasicEnum.IOT_LIST_PRODUCT_ERROR);
        }
        List<QueryProductListResponseBody.QueryProductListResponseBodyDataListProductInfo> productInfo = response.getBody().getData().getList().getProductInfo();
        // 转换
        List<ProductVo> productVos = BeanUtil.copyToList(productInfo, ProductVo.class);

        if (ObjectUtil.isEmpty(productVos)) {
            throw new RuntimeException("iot产品列表为空");
        }
        // 储存到redis中
        redisTemplate.opsForValue().set(CacheConstants.ALL_PRODUCT_KEY, JSONUtil.toJsonStr(productVos));
    }

    /**
     * 查询所有产品列表
     *
     * @return
     */
    @Override
    public List<ProductVo> gerAllProductList() {
        String json = redisTemplate.opsForValue().get(CacheConstants.ALL_PRODUCT_KEY);
        if (ObjectUtil.isEmpty(json)) {
            throw new RuntimeException("iot产品列表为空");
        }
        return JSONUtil.toList(json, ProductVo.class);
    }

    /**
     * 注册设备
     */
    @Override
    public void registerDevice(DeviceDto deviceDto) {
        // 判断设备名称是否重复
        boolean ret = deviceMapper.checkIsSameByDeviceName(deviceDto.getDeviceName());
        if (ret) {
            throw new BaseException(BasicEnum.DEVICE_NAME_EXIST);
        }

        // 不重复, iot新增设备
        RegisterDeviceRequest registerDeviceRequest = deviceDto.getRegisterDeviceRequest();
        registerDeviceRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        RegisterDeviceResponse deviceResponse;
        try {
            deviceResponse = client.registerDevice(registerDeviceRequest);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }

        // 如果新增失败, 抛出异常
        if (!deviceResponse.getBody().getSuccess()) {
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }

        // 查询产品设置产品名称到设备对象
        QueryProductRequest productRequest = new QueryProductRequest();
        productRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        productRequest.setProductKey(deviceResponse.getBody().getData().getProductKey());
        QueryProductResponse productResponse = null;
        try {
            productResponse = client.queryProduct(productRequest);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_PRODUCT_ERROR);
        }
        if (!productResponse.getBody().getSuccess()) {
            throw new BaseException(BasicEnum.IOT_QUERY_PRODUCT_ERROR);
        }

        // 判断位置类型是否是0(位置类型 0：随身设备 1：固定设备)
        Device device = BeanUtil.toBean(deviceDto, Device.class);
        device.setHaveEntranceGuard(0);
        device.setProductName(productResponse.getBody().getData().getProductName());
        device.setIotId(deviceResponse.getBody().getData().getIotId());
        if (deviceDto.getLocationType().equals(DeviceLocationTypeEnum.PORTABLE_DEVICE.getOrdinal())) {
            // 设置物理位置为-1
            device.setPhysicalLocationType(DevicePhysicalLocationTypeEnum.ELDER.getOrdinal());
        }

        // 存储到数据库
        try {
            deviceMapper.insert(device);
        } catch (Exception e) {
            // 如果新增失败, 删除物联网的设备数据
            DeleteDeviceRequest deleteDeviceRequest = new DeleteDeviceRequest();
            deleteDeviceRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
            deleteDeviceRequest.setIotId(device.getIotId());
            DeleteDeviceResponse deleteDeviceResponse = null;
            try {
                deleteDeviceResponse = client.deleteDevice(deleteDeviceRequest);
            } catch (Exception ex) {
                DeleteDeviceRequest deleteDeviceRequest2 = new DeleteDeviceRequest();
                deleteDeviceRequest2.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
                deleteDeviceRequest2.setDeviceName(device.getDeviceName());
                deleteDeviceRequest2.setProductKey(device.getProductKey());
                try {
                    client.deleteDevice(deleteDeviceRequest2);
                } catch (Exception exc) {
                    throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
                }
            }
        }
    }

    /**
     * 分页查询设备列表
     *
     * @param pageNum
     * @param pageSize
     * @param deviceName
     * @param locationType
     * @param productKey
     * @return
     */
    @Override
    public PageResponse<DeviceVo> pageQueryDevice(Integer pageNum, Integer pageSize, String deviceName, Integer locationType, String productKey) {
        PageHelper.startPage(pageNum, pageSize);
        Page<Device> page = deviceMapper.pageQueryDevice(deviceName, locationType, productKey);
        return PageResponse.of(page, DeviceVo.class);
    }

    /**
     * 查询设备详细数据
     *
     * @param iotId
     * @param productKey
     * @return
     */
    @Override
    public DeviceVo QueryDeviceDetail(DeviceDto deviceDto) {
        String iotId = deviceDto.getIotId();
        String productKey = deviceDto.getProductKey();
        // 1.去物联网平台查询设备具体数据
        QueryDeviceDetailRequest deviceDetailRequest = new QueryDeviceDetailRequest();
        deviceDetailRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        deviceDetailRequest.setIotId(iotId);
        QueryDeviceDetailResponse deviceDetailResponse;
        try {
            deviceDetailResponse = client.queryDeviceDetail(deviceDetailRequest);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }
        if (!deviceDetailResponse.getBody().getSuccess()) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }
        DeviceVo aliDeviceVo = BeanUtil.toBean(deviceDetailResponse.getBody().getData(), DeviceVo.class);
        // 2.去数据库查询设备相关数据
        Device device = deviceMapper.selectByIotId(iotId);
        if (ObjectUtil.isEmpty(device)) {
            throw new RuntimeException("发生异常, 数据库不存在该设备");
        }
        // 3.合并返回
        DeviceVo deviceVo2 = BeanUtil.toBean(device, DeviceVo.class);
        CopyOptions copyOptions = CopyOptions.create().setIgnoreNullValue(true);
        BeanUtil.copyProperties(deviceVo2, aliDeviceVo, copyOptions);
        return aliDeviceVo;
    }

    /**
     * 查询指定设备的物模型运行状态
     *
     * @param deviceDto
     * @return
     */
    @Override
    public QueryDevicePropertyStatusResponseBody.QueryDevicePropertyStatusResponseBodyData QueryDevicePropertyStatus(DeviceDto deviceDto) {
        QueryDevicePropertyStatusRequest queryDevicePropertyStatusRequest = new QueryDevicePropertyStatusRequest();
        queryDevicePropertyStatusRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        queryDevicePropertyStatusRequest.setDeviceName(deviceDto.getDeviceName());
        queryDevicePropertyStatusRequest.setProductKey(deviceDto.getProductKey());
        QueryDevicePropertyStatusResponse response;
        try {
            response = client.queryDevicePropertyStatus(queryDevicePropertyStatusRequest);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_PROPERTY_STATUS_ERROR);
        }
        if (!response.getBody().getSuccess()) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_PROPERTY_STATUS_ERROR);
        }
        return response.getBody().getData();
    }

    /**
     * 查看指定产品的已发布物模型中的功能定义详情
     *
     * @param deviceDto
     * @return
     */
    @Override
    public QueryThingModelPublishedResponseBody.QueryThingModelPublishedResponseBodyData QueryThingModelPublished(DeviceDto deviceDto) {
        QueryThingModelPublishedRequest request = new QueryThingModelPublishedRequest();
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        request.setProductKey(deviceDto.getProductKey());
        QueryThingModelPublishedResponse response;
        try {
            response = client.queryThingModelPublished(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.QUERY_THING_MODEL_PUBLISHED_ERROR);
        }
        if (!response.getBody().getSuccess()) {
            throw new BaseException(BasicEnum.QUERY_THING_MODEL_PUBLISHED_ERROR);
        }
        return response.getBody().getData();
    }

    /**
     * 修改设备备注名称
     *
     * @param deviceDto
     */
    @Override
    public void updateDevice(DeviceDto deviceDto) {
        // 先更新物联网平台的设备信息
        BatchUpdateDeviceNicknameRequest request = new BatchUpdateDeviceNicknameRequest();
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo info = new BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo();
        info.setIotId(deviceDto.getIotId());
        info.setNickname(deviceDto.getNickname());
        request.setDeviceNicknameInfo(List.of(info));
        BatchUpdateDeviceNicknameResponse response;
        try {
            response = client.batchUpdateDeviceNickname(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
        }
        if (!response.getBody().getSuccess()){
            throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
        }
        // 判断location_type, 位置类型 0：随身设备 1：固定设备
        Device device = BeanUtil.toBean(deviceDto, Device.class);
        if (device.getLocationType().equals(DeviceLocationTypeEnum.PORTABLE_DEVICE.getOrdinal())) {
            device.setPhysicalLocationType(DevicePhysicalLocationTypeEnum.ELDER.getOrdinal());
        }
        // 更新
        try {
            deviceMapper.updateDevice(device);
        } catch (Exception e) {
            throw new RuntimeException("修改失败");
        }
    }

    /**
     * 删除设备
     * @param deviceDto
     */
    @Override
    public void deleteDevice(DeviceDto deviceDto) {
        // 判断该设备是否同时在数据库和物联网平台存在
        isExistInAliAndMysql(deviceDto.getIotId());

        // 删除数据库中的设备
        Device device = deviceMapper.selectByIotId(deviceDto.getIotId());
        try {
            deviceMapper.deleteByIotId(deviceDto.getIotId());
        } catch (Exception e) {
            throw new BaseException(BasicEnum.DELETE_SERVICE_FAIL);
        }

        // 删除物联网平台的设备
        DeleteDeviceRequest request = new DeleteDeviceRequest();
        request.setIotId(deviceDto.getIotId());
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        DeleteDeviceResponse response;
        try {
            response = client.deleteDevice(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
        }
        if (!response.getBody().getSuccess()) {
            // 如果物联网删除失败, 则数据库恢复数据
            deviceMapper.insert(device);
            throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
        }
    }

    /**
     * 根据设备iotId判断是否同时在数据库和物联网平台都存在
     * @param iotId
     * @return
     */
    public boolean isExistInAliAndMysql(String iotId) {
        Device device = deviceMapper.selectByIotId(iotId);
        if (ObjectUtil.isEmpty(device)) {
            throw new RuntimeException("数据库不存在该设备");
        }
        GetDeviceStatusRequest request = new GetDeviceStatusRequest();
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        request.setIotId(iotId);
        GetDeviceStatusResponse response;
        try {
            response = client.getDeviceStatus(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }
        if (!response.getBody().getSuccess()){
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }
        return true;
    }
}
